package com.db4o.internal.odbgen;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;

import com.db4o.odbgen.OdbgenException;

/**
 * 
 * Contains static utility methods related directly to templates.
 * @author liviug
 */
public class TemplatesUtils {
    
    private static VelocityEngine _velocityEngine;

    /**
     * Returns a velocity template from a jar file. 
     * @param templateName This is a relative path to the template. The path is relative to the
     * root of the jar file containing the standard templates.
     * @param standardTemplatesJar The path to the jar file containing the standard templates.
     * The file must be in the classpath.
     * @throws OdbgenException
     */
    public static Template getTemplateJar(String templateName, String standardTemplatesJar) throws OdbgenException{
        
        //Get the velocity engine (create one if no one exists)
        VelocityEngine ve = null;
        if(TemplatesUtils._velocityEngine==null){
            TemplatesUtils._velocityEngine = TemplatesUtils.createVelocityEngine(standardTemplatesJar);
        }
        ve = TemplatesUtils._velocityEngine;

        //Get the template.
        Template t;
        try{
            t = ve.getTemplate(templateName);
        }
        catch( ResourceNotFoundException rnfe ){
            throw new OdbgenException(
                    rnfe, 
                    "Could not find '%s' template inside '%s'.",
                    templateName,
                    standardTemplatesJar
                    );
        }
        catch( ParseErrorException pe ){
            // syntax error: problem parsing the template
            throw new OdbgenException(
                    pe, 
                    "Syntax error inside  '%s/%s' template.",
                    standardTemplatesJar,
                    templateName
                    );
        }
        catch( MethodInvocationException mie ){
            //something invoked in the template
            //threw an exception
            throw new OdbgenException(
                    mie, 
                    "Error while getting '%s/%s' template.",
                    standardTemplatesJar,
                    templateName
                    );
        }
        catch( Exception e ){
            throw new OdbgenException(
                    e, 
                    "Error while getting '%s/%s' template.",
                    standardTemplatesJar,
                    templateName
                    );
        }
        
        return t;
    }
    
    /**
     * Used to create a new velocity engine instance.
     * @param javaPath The path to the standard template jar.
     * @throws OdbgenException
     */
    private static VelocityEngine createVelocityEngine(String jarPath) throws OdbgenException{
        
        VelocityEngine ve = null;
        String jarUri = new File(jarPath).toURI().toString(); 
        try {
            ve = new VelocityEngine();
            ve.setProperty("resource.loader", "jar");
            ve.setProperty("jar.resource.loader.class", "org.apache.velocity.runtime.resource.loader.JarResourceLoader");
            ve.setProperty("jar.resource.loader.path", "jar:"+jarUri);
            ve.init();
        } 
        catch (Exception e) {
            throw new OdbgenException(e, "Could not initialize templates from inside '%s'.", jarPath);
        }
        
        return ve;
    }
    



    /**
     * Convenient method to merge a template and a context.
     * @return The result of the merge.
     */
    public static String merge(Template template, VelocityContext context) throws OdbgenException{
        StringWriter res = new StringWriter();
        try{
            template.merge( context, res );
        }
        catch(IOException e){
            throw new OdbgenException(e, "An error occured while trying to merge a Velocity template.");
        }
        return res.toString();
    }
    
}
